package com.bite.friend.service.exam.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.bite.common.core.constants.Constants;
import com.bite.common.core.domain.TableDataInfo;
import com.bite.common.core.utils.ThreadLocalUtil;
import com.bite.friend.domain.exam.ExamRankDTO;
import com.bite.friend.domain.exam.dto.ExamQueryDTO;
import com.bite.friend.domain.exam.vo.ExamRankVO;
import com.bite.friend.domain.exam.vo.ExamVO;
import com.bite.friend.domain.user.vo.UserVO;
import com.bite.friend.manager.ExamCacheManager;
import com.bite.friend.manager.UserCacheManager;
import com.bite.friend.mapper.exam.ExamMapper;
import com.bite.friend.mapper.user.UserExamMapper;
import com.bite.friend.service.exam.IExamService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ExamServiceImpl  implements IExamService {
    @Autowired
    private ExamMapper examMapper;
    @Autowired
    private ExamCacheManager examCacheManager;
    @Autowired
    private UserExamMapper userExamMapper;
    @Autowired
    private UserCacheManager userCacheManager;

    @Override
    public List<ExamVO> list(ExamQueryDTO examQueryDto) {
        PageHelper.startPage(examQueryDto.getPageNum(),examQueryDto.getPageSize());
        //question表太多的可变，导致他的SQL会有些复杂，而且维护麻烦
        List<ExamVO> questionVOList =examMapper.selectExamList(examQueryDto);
        return questionVOList ;
    }
    @Override
    public TableDataInfo redisList(ExamQueryDTO examQueryDto) {
/**     从redis中获取竞赛列表的数据。如何确保老数据也在储存里面，在查询里面就处理，如果在redis里没有任何数据，
        如果说查不出任何数据，从数据库中查询，如果数据库里面有,然后再去同步一下数据(把数据库里面的同步到缓存)，然后再去返回数据
        代码改完之后，应该此时就能把老数据全部同步到redis里面(先从redis里面查，没数据再去查数据库)，但是来了一个人
        你刚发布完事，来个人立马发布一条数据，发布数据以后，此时没人查询列表，此时发布的这个一条数据进入缓存，redis有数据
        有一条，再去查询就直接得到这条数据，不是没数据的，而是有数据，因此就不去数据库里查，把老数据又没同步过来
        因此，我们可以处理一下，限制一下用户行为，发布之前，处理完之前，不让用户使用，把老数据同步上，再去插入，
        或者就算你插入了，我可以直接清除缓存，控制一下就又一致了。
*/
        //从redis当中获取，竞赛列表的数据
        Long total=examCacheManager.getListSize(examQueryDto.getType(),null);
        List<ExamVO>examVOList;

        if(total==null||total==0){
            //调用方法,把数据库里面东西返回给前端了
           examVOList=list(examQueryDto);
           //刷新缓存需要有针对性的，假如未完赛，还是完赛，将数据库的东西，同步给缓存
           examCacheManager.refreshCache(examQueryDto.getType(),null);
           total=new PageInfo<>(examVOList).getTotal();
        }else {
            //从redis获取到数据就好了
           examVOList=examCacheManager.getExamVOList(examQueryDto,null);
            //为什么又要调用一遍，原因在于从redis获取数据，假如异常情况，我会刷新同步一次，redis里数据就会又变化，那么你就要重新获取一下
            total=examCacheManager.getListSize(examQueryDto.getType(),null);
        }
        if(CollectionUtils.isEmpty(examVOList)){
            return TableDataInfo.empty();
        }
       assembleExamVOList(examVOList);
        return TableDataInfo.success(examVOList,total);
    }

    @Override
    public TableDataInfo rankList(ExamRankDTO examRankDTO) {
        Long total = examCacheManager.getRankListSize(examRankDTO.getExamId());
        List<ExamRankVO> examRankVOList;
        if (total == null || total <= 0) {
            //调用方法,把数据库里面东西返回给前端了
            PageHelper.startPage(examRankDTO.getPageNum(), examRankDTO.getPageSize());
            examRankVOList = userExamMapper.selectExamRankList(examRankDTO.getExamId());
            //刷新缓存需要有针对性的，哪个竞赛没有，刷新哪个，不是全刷新
            examCacheManager.refreshExamRankCache(examRankDTO.getExamId());
            total = new PageInfo<>(examRankVOList).getTotal();
        } else {
            //从redis获取到数据就好了
            examRankVOList = examCacheManager.getExamRankList(examRankDTO);
        }
            //为什么又要调用一遍，原因在于从redis获取数据，假如异常情况，我会刷新同步一次，redis里数据就会又变化，那么你就要重新获取一下
            if (CollectionUtils.isEmpty(examRankVOList)) {
                return TableDataInfo.empty();
            }
            assembleExamRankVOList(examRankVOList);
            return TableDataInfo.success(examRankVOList, total);
        }
    private  void assembleExamRankVOList(List<ExamRankVO>examRankVOList){
        if(CollectionUtil.isEmpty(examRankVOList)){
            return;
        }
        for (ExamRankVO examRankVO:examRankVOList){
           Long userId=examRankVO.getUserId();
           UserVO user=userCacheManager.getUserById(userId);
           examRankVO.setNickName(user.getNickName());

        }
    }




    @Override
    public String getFirstQuestion(long examId) {
      checkAndRefresh(examId);
        return examCacheManager.getFirstQuestion(examId).toString();
    }

    @Override
    public String preQuestion(Long examId, Long questionId) {
     checkAndRefresh(examId);
        return examCacheManager.preQuestion(examId,questionId).toString();
    }

    @Override
    public String nextQuestion(Long examId, Long questionId) {
       checkAndRefresh(examId);
        return examCacheManager.nextQuestion(examId,questionId).toString();
    }
    private void   checkAndRefresh(Long examId){
        Long listSize=examCacheManager.getExamQuestionListSize(examId);
        if(listSize==null||listSize<=0){
            examCacheManager.refreshExamQuestionCache(examId);
        }
    }


    private void assembleExamVOList(List<ExamVO> examVOList) {
        Long userId=ThreadLocalUtil.get(Constants.USER_ID,Long.class);
        //把当前用户参加的所有竞赛都拿出来
        List<Long>userExamList=examCacheManager.getAllUserExamList(userId);
        if(CollectionUtil.isEmpty(userExamList)){
            return;
        }
        for(ExamVO examVO:examVOList){
            if(userExamList.contains(examVO.getExamId())){
                //假如包含置为true
                examVO.setEnter(true);
            }
        }
    }
}
